const {
	SyncHook,
	AsyncParallelHook,
} = require("tapable");

function mockPromise(result) {
  return new Promise(resolve => {
    setTimeout(() => resolve(result), 1000)
  })
}
 
const hook = new SyncHook(["arg1", "arg2", "arg3"]);
class Car {
	constructor() {
		this.hooks = {
			accelerate: new SyncHook(["newSpeed"]),
			brake: new SyncHook(),
			calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])
		};
  }

  callBrake() {
    this.hooks.brake.call();
  }
  /**
	  * You won't get returned value from SyncHook or AsyncParallelHook,
	  * to do that, use SyncWaterfallHook and AsyncSeriesWaterfallHook respectively
	 **/

	setSpeed(newSpeed) {
		// following call returns undefined even when you returned values
		this.hooks.accelerate.call(newSpeed);
  }
  
  useNavigationSystemPromise(source, target, routesList) {
		return this.hooks.calculateRoutes.promise(source, target, routesList).then((res) => {
			// res is undefined for AsyncParallelHook
			return mockPromise(source, target, routesList)
		});
  }
  
  useNavigationSystemAsync(source, target, callback) {
		const routesList = new List();
		this.hooks.calculateRoutes.callAsync(source, target, routesList, err => {
			if(err) return callback(err);
			callback(null, routesList.getRoutes());
		});
	}

}

const myCar = new Car();

// Use the tap method to add a consument
myCar.hooks.brake.tap("WarningLampPlugin", () => console.log('tab hooks.brake'));

// You may receive arguments:
myCar.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`));

// For sync hooks, tap is the only valid method to add a plugin. Async hooks also support async plugins:
myCar.hooks.calculateRoutes.tapPromise("GoogleMapsPlugin", (source, target, routesList) => {
	// return a promise
  console.log('calculateRoutes---' + routesList.length)
  return mockPromise(source, target, routesList)
});

// myCar.hooks.calculateRoutes.tapAsync("BingMapsPlugin", (source, target, routesList, callback) => {
// 	bing.findRoute(source, target, (err, route) => {
// 		if(err) return callback(err);
// 		routesList.add(route);
// 		// call the callback
// 		callback();
// 	});
// });


// tap hooks.brake
myCar.callBrake();

myCar.setSpeed(1000);

myCar.useNavigationSystemPromise('source', 'target', [1, 2, 3])
